package com.piece.file.client.sftp;

import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.piece.core.framework.exception.ErrorCode;
import com.piece.core.framework.exception.FrameWorkException;
import com.piece.core.framework.util.file.FileUtil;
import com.piece.core.framework.util.security.coder.MD5Coder;
import com.piece.file.client.AbstractFileClient;
import com.piece.file.model.TbSysFile;
import lombok.extern.slf4j.Slf4j;
import java.io.*;
import java.util.List;

/**
 * Sftp文件客户端
 */
@Slf4j
public class SftpFileClient extends AbstractFileClient<SftpFileClientConfig> {

    private Session session;
    private ChannelSftp client;

    public SftpFileClient(String name, SftpFileClientConfig config) {
        super(name, config);
    }

    @Override
    protected void doInit() {
        if (!config.getBasePath().endsWith(File.separator)) {
            config.setBasePath(config.getBasePath() + File.separator);
        }

        // 创建JSch对象,连接FTP服务器
        try {
            JSch jsch = new JSch();
            session = jsch.getSession(config.getAccessKey(), config.getDomain(), config.getPort());
            session.setPassword(config.getAccessSecret());
            // 为Session对象设置properties
            session.setConfig("StrictHostKeyChecking", "no");
        } catch (JSchException e) {
            log.error("创建Sftp服务器异常：{}", e.getMessage());
        }
    }

    private boolean connect() {
        try {
            // 通过Session建立链接
            session.connect();
            // 打开SFTP通道
            client = (ChannelSftp) session.openChannel("sftp");
            client.connect();
        } catch (Exception e) {
            log.error("获取Sftp连接异常：{}", e.getMessage());
            return false;
        }
        return true;
    }

    private void disconnect() {
        if (null != client) {
            client.disconnect();
            client = null;
        }
        if (null != session) {
            session.disconnect();
        }
    }

    @Override
    public TbSysFile writeToServerStore(byte[] bytes, String path, String name, String md5, boolean stat) throws Exception {
        TbSysFile file = new TbSysFile();
        file.setMd5(md5);

        try {
            List<TbSysFile> existFiles = tbSysFileService.findFileByMd5(md5);
            if (null != existFiles && existFiles.size() > 0) {
                file.setServerId("sftp");
                file.setServerFileName(existFiles.get(0).getServerFileName());
                file.setServerPath(existFiles.get(0).getServerPath());
                return file;
            }

            if (!connect()) {
                throw new FrameWorkException(ErrorCode.UPLOAD);
            }

            String workDirectory = path;
            if (!path.startsWith(config.getBasePath())) {
                workDirectory = config.getBasePath() + path;
            }
            // 上传文件
            client.put(new ByteArrayInputStream(bytes), workDirectory + name);
            file.setServerId("sftp");
            file.setServerFileName(name);
            file.setServerPath(workDirectory);
            return file;
        } catch (Exception e) {
            log.error("上传Sftp文件异常：{}", e.getMessage());
            throw new FrameWorkException(ErrorCode.UPLOAD);
        } finally {
            disconnect();
        }
    }

    @Override
    public InputStream downloadFile(TbSysFile file) throws Exception {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try {
            String remotePath = file.getServerPath();
            String fileName = file.getServerFileName();
            if (!connect()) {
                throw new FrameWorkException(ErrorCode.DOWNLOAD);
            }

            client.get(remotePath + fileName, os);
            byte[] bytes = os.toByteArray();
            return new ByteArrayInputStream(bytes);
        } catch (Exception e) {
            log.error("下载Sftp文件异常：{}", e.getMessage());
            throw new FrameWorkException(ErrorCode.DOWNLOAD);
        } finally {
            disconnect();
            os.close();
        }
    }

    @Override
    public void updateFile(TbSysFile file) {
        try {
            // 删除原文件
            deleteServerFile(file);
            byte[] bytes = FileUtil.toByte(file.getFileInputStream());
            String md5 = MD5Coder.md5File(bytes);
            // 重新上传文件
            writeToServerStore(bytes, file.getServerPath(), file.getServerFileName(), md5, false);
        } catch (Exception e) {
            log.error("更新FTP文件异常：{}", e.getMessage());
            throw new FrameWorkException(new ErrorCode(e.getMessage()));
        }
    }

    @Override
    public void deleteFile(TbSysFile file) throws Exception {
        deleteTbSysFile(file);
        deleteServerFile(file);
    }

    private void deleteServerFile(TbSysFile file) {
        if (checkMd5(file)) {
            return;
        }

        try {
            if (!connect()) {
                throw new FrameWorkException(ErrorCode.DELETE);
            }

            String remotePath = file.getServerPath();
            String fileName = file.getServerFileName();
            client.rm(remotePath + fileName);
        } catch (Exception e) {
            log.error("删除Sftp文件异常：{}", e.getMessage());
            throw new FrameWorkException(ErrorCode.DELETE);
        } finally {
            disconnect();
        }
    }
}
